/***********************************************
 This file is part of redia-bapps-main-ios.
 
 Copyright (c) 2015 Redia A/S
 
 Redia-bapps-main-ios is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.
 
 Redia-bapps-main-ios is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with redia-bapps-main-ios.  If not, see <http://www.gnu.org/licenses/>.
 
 *********************************************** */

//
//  BACoverUrlMemoryCache.m
//  redia-bapps-ios
//
//  Created by Henrik Lynbech on 15/10/13.
//  Copyright (c) 2013 redia. All rights reserved.
//

#import "BACoverUrlAndAvailabilityMemoryCache.h"
#import "InfoGalleriImageUrlUtils.h"
#import "LazyLoadManager.h"

@interface BACoverUrlAndAvailabilityMemoryCache () {
    NSCache* availabilityRecords;
    NSCache* coverUrls;
    NSCache* searchResultCoverImages;
    
    NSMutableArray* coverUrlStringFetchRequestQueue;
    NSMutableSet* coverUrlStringsCurrentlyFetching;
}


@end


@implementation BACoverUrlAndAvailabilityMemoryCache

SINGLETON_IMPL_GCD(BACoverUrlAndAvailabilityMemoryCache)

- (id)init
{
    self = [super init];
    if (self) {
        /* The following code allows for multiple searches to share a cached lookup
         of coveruls and availability records. To avoid an ever-growing
         memory usage, the cache is limited to 1000 unique entries
         for each dicionary, which has a low to moderate mem usage and will rarely have
         noticable user experience impact. 1000 entries is the equivalent of 50 search calls with
         20 unique successful non-empty hits for each array.
         */
        availabilityRecords = [[NSCache alloc] init];
        [availabilityRecords setCountLimit:1000];
        
        coverUrls = [[NSCache alloc] init];
        [coverUrls setCountLimit:1000];
        
        searchResultCoverImages = [[NSCache alloc] init];
        [searchResultCoverImages setCountLimit:50];
        
        coverUrlStringFetchRequestQueue = [NSMutableArray new];
        coverUrlStringsCurrentlyFetching = [NSMutableSet new];
    }
    return self;
}

-(void)appendAvailabilityRecords:(NSDictionary *)availabilities
{
    
    //run through keys, only storing the ones that had succesful response from backend
    for (NSString* key in [availabilities allKeys]) {
        BAStandardResultObject* std_result_for_availability = [availabilities objectForKey:key];
        
        if (std_result_for_availability != nil && std_result_for_availability.result) {
            BAAvailability* availabilityInfo = std_result_for_availability.parsedData;
            if (availabilityInfo) {
                [availabilityRecords setObject:availabilityInfo forKey:key];
            }
            
        }
    }
}

-(BAAvailability *)getAvailabilityForIdentifier:(NSString *)identifier
{
    if (identifier!=nil && [identifier length]>0) {
        return [availabilityRecords objectForKey:identifier];
    }
    return nil;
}

-(void)fetchCoverUrlsForIdentifiers:(NSArray*)identifiers {
    NSMutableArray* newIdentifiers = [NSMutableArray new];
    
    for (NSString* requestedId in identifiers) {
        if ([coverUrls objectForKey:requestedId]==nil) {
            //coverurl not already found for id
            [newIdentifiers addObject:requestedId];
        }
    }
    
    if ([newIdentifiers count]>0) {
        DLog(@"fetching %d new coverurls",[identifiers count]);
        
        [BARPCManager getCoverUrlsAsyncFromView:nil
                                coverUrlQueries:newIdentifiers
                                    resultBlock:^(NSDictionary* result) {
                                        [self appendCoverUrls:result];
                                    }
                                     errorBlock:^(int errorCode, NSString *errorMessage) {
                                         DLog(@"error fetching coverurls %d %@",errorCode, errorMessage);
                                     }];
    }

}

-(void)fetchCoverImagesForIdentifiers:(NSArray*)identifiers
{
    for (NSString* identifier in identifiers) {
        if ([searchResultCoverImages objectForKey:identifier]==nil) {
            //only fetch if image not already there
            
            BACoverUrl* coverUrlInfo = [self getCoverUrlForIdentifier:identifier];
            if (coverUrlInfo != nil && [coverUrlInfo.url length]>0) {
                bool isIpad = RD_IS_IPAD;
                
                NSString* resize_url = [InfoGalleriImageUrlUtils getResizedImageUrl:coverUrlInfo.url
                                                                            toWidth:isIpad ? 59 : 50
                                                                           toHeight:isIpad ? 97 : 75
                                                                       usingQuality:7
                                                                           withMode:IMAGE_URL_UTILS_RESIZE_MODE_BOUNDING_BOX
                                                                       outputFormat:@"jpeg"
                                                                  doubleUpForRetina:YES];

                if (![coverUrlStringsCurrentlyFetching containsObject:resize_url]) {
                    //only fetch if not currently fetching
                    
                    //FIXME: use a queue and only fetch two newest images at a time
                    [coverUrlStringsCurrentlyFetching addObject:resize_url];
                    DLog(@"start fetch cover for identifier %@",identifier);
                    [[LazyLoadManager instance] lazyLoadUIImageFromUrl:resize_url
                                                             withOwner:self
                                                     setScaleforRetina:YES
                                                             onSuccess:^(UIImage *image) {
                                                                 [self addSearchResultCellSizedCoverImage:image forIdentifier:identifier];

                                                                 [coverUrlStringsCurrentlyFetching removeObject:resize_url];
                                                             }
                                                               onError:^(LazyLoaderErrorCode errorCode, NSString *errorMessage) {
                                                                   [coverUrlStringsCurrentlyFetching removeObject:resize_url];
                                                               }
                                                              onCancel:^{
                                                                   [coverUrlStringsCurrentlyFetching removeObject:resize_url];
                                                              }
                     ];

                }
            }
        }
    }
}

-(void)fetchNextCoverImageFromQueue
{
    //todo: fetch from queue
}

-(void)appendCoverUrls:(NSDictionary *)newCoverUrls
{
    //run through keys, only storing new ones that had succesful response from backend
    for (NSString* key in [newCoverUrls allKeys]) {
        if ([coverUrls objectForKey:key]!=nil) {
            //key was already in cache
            continue;
        } else {
            BAStandardResultObject* std_result_for_coverurls = [newCoverUrls objectForKey:key];
            
            if (std_result_for_coverurls != nil && std_result_for_coverurls.result) {
                BACoverUrl* coverurl_info = std_result_for_coverurls.parsedData;
                if (coverurl_info && [coverurl_info.url length]>0) {
                    [coverUrls setObject:coverurl_info forKey:key];
                }
            }
        }
    }
    
    [[NSNotificationCenter defaultCenter] postNotificationName:BA_COVER_URL_CACHE_COVER_URLS_ARRIVED object:nil];
}

-(BACoverUrl*)getCoverUrlForIdentifier:(NSString*)identifier
{
    if (identifier!=nil && [identifier length]>0) {
        return [coverUrls objectForKey:identifier];
    }
    return nil;
}

-(void)addSearchResultCellSizedCoverImage:(UIImage*)image forIdentifier:(NSString*)identifier
{
    [searchResultCoverImages setObject:image forKey:identifier];
    DLog(@"image arrived for id %@",identifier);
    [[NSNotificationCenter defaultCenter] postNotificationName:BA_COVER_URL_CACHE_IMAGE_LOADED object:nil];
}

-(UIImage*)getSearchResultCellSizedCoverImageForIdentifier:(NSString*)identifier
{
    return [searchResultCoverImages objectForKey:identifier];
}

/* dep: moved code
-(void)lazyloadImageFromIdentifier:(NSString *)identifier owner:(id)owner onSuccess:(LLSuccessBlock)successBlock onError:(LLErrorBlock)errorBlock
{
    if ([identifier length]==0) {
        if (errorBlock!=nil) {
            errorBlock(-1,@"No identifier");
        }
        return;
    }
    
    BACoverUrlAndAvailabilityMemoryCache* cache = [BACoverUrlAndAvailabilityMemoryCache instance];

    UIImage* cached_image = [cache getSearchResultCellSizedCoverImageForIdentifier:identifier];
    if (cached_image) {
        if (successBlock!=nil) {
            successBlock(cached_image);
        }
    } else {
        BACoverUrl* coverurl_info = [cache getCoverUrlForIdentifier:identifier];
        
        if (coverurl_info) {
            if (!coverurl_info.isFetchingImage) {
                coverurl_info.isFetchingImage=TRUE;
                
                bool isIpad = RD_IS_IPAD;
                
                NSString* resize_url = [InfoGalleriImageUrlUtils getResizedImageUrl:coverurl_info.url
                                                                            toWidth:isIpad ? 59 : 50
                                                                           toHeight:isIpad ? 97 : 75
                                                                       usingQuality:7
                                                                           withMode:IMAGE_URL_UTILS_RESIZE_MODE_BOUNDING_BOX
                                                                       outputFormat:@"jpeg"
                                                                  doubleUpForRetina:YES];
                
                [[LazyLoadManager instance] lazyLoadUIImageFromUrl:resize_url
                                                         withOwner:owner
                                                 setScaleforRetina:YES
                                                         onSuccess:^(UIImage *image) {
                                                             [cache addSearchResultCellSizedCoverImage:image forIdentifier:identifier];
                                                             if (successBlock!=nil) {
                                                                 successBlock(image);
                                                             }
                                                             coverurl_info.isFetchingImage = NO;
                                                         }
                                                           onError:^(LazyLoaderErrorCode errorCode, NSString *errorMessage) {
                                                               if (errorBlock!=nil) {
                                                                   errorBlock(errorCode, errorMessage);
                                                               }
                                                               coverurl_info.isFetchingImage = NO;
                                                           } onCancel:^{
                                                               coverurl_info.isFetchingImage = NO;
                                                           }
                 ];
            }
        }
    }

}
 */

@end
